/******************************************************************************
* Copyright (c) 2007 Alexandru Scvortov
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/


#include <string.h>

#include "common.h"

static DocNode* doc_node_new() {
    DocNode *tmp = (DocNode *)malloc(sizeof(DocNode));

    tmp->type = DocNodeUnknown;
    tmp->value = 0;
    tmp->indent_level = 0;
    tmp->next = 0;

    return tmp;
}

DocNode* doc_node_remove(DocNode *dn) {
    if (!dn)
        return 0;

    check_and_free(dn->value);

    check_and_free(dn);

    return dn;
}

static CommentNode* comment_node_new() {
    CommentNode *tmp = (CommentNode*)malloc(sizeof(CommentNode));

    tmp->child = 0;
    tmp->next = 0;
    tmp->next_for_func = 0;
    tmp->assigned = 0;

    return tmp;
}

CommentNode* comment_node_remove(CommentNode *cn) {
    if (!cn)
        return 0;

    DocNode *it;
    it = cn->child;
    while (it) {
        DocNode *next = it->next;
        doc_node_remove(it);
        it = next;
    }

    check_and_free(cn);

    return cn;
}

static void comment_parse_command(DocNode *n, char *text) {
    char *rest = strchr(text, ' ');
    *rest = 0;

    if (0 == strcmp(text, "@return"))
        n->type = DocNodeReturn;
    else if (0 == strcmp(text, "@projectname")) {
        text = rest + 1;
        project_name = (char*)malloc((strlen(text) + 1) * sizeof(char));
        strcpy(project_name, text);
        return;
    } else if (0 == strcmp(text, "@projectversion")) {
        text = rest + 1;
        project_version = (char*)malloc((strlen(text) + 1) * sizeof(char));
        strcpy(project_version, text);
        return;
    } else if (0 == strcmp(text, "@author")) {
        text = rest + 1;
        author = (char*)malloc((strlen(text) + 1) * sizeof(char));
        strcpy(author, text);
        return;
    } else if (0 == strcmp(text, "@site")) {
        text = rest + 1;
        site = (char*)malloc((strlen(text) + 1) * sizeof(char));
        strcpy(site, text);
        return;
    }

    text = rest + 1;
    n->value = (char*)malloc((strlen(text) + 1) * sizeof(char));
    strcpy(n->value, text);
}

static void comment_process_text(DocNode *n, char *text) {
    n->indent_level = 0;
    while ((' ' == text[0]) || ('\t' == text[0])) {
        ++(n->indent_level);
        ++text;
    }

    if ('@' == text[0]) {
        // Text is a command (eg. @return)
        comment_parse_command(n, text);
    } else {
        // Text is plain
        n->type = DocNodeText;
        n->value = (char*)malloc((strlen(text) + 1) * sizeof(char));
        strcpy(n->value, text);
    }
}

static DocNode* split_comment(char *text) {
    if (!text || (!text[0]))
        return 0;

    DocNode *tmp = doc_node_new();
    char *nl = strchr(text, '\n');
    if (!nl)
        comment_process_text(tmp, text);
    else {
        if ('\n' == *(nl + 1)) {
            *nl = 0;
            ++nl;
            *nl = 0;
            ++nl;
            comment_process_text(tmp, text);
            tmp->next = split_comment(nl);
        } else {
            *nl = ' ';
            doc_node_remove(tmp);
            tmp = split_comment(text);
        }
    }

    return tmp;
}

void parse_comment() {
    CommentNode *tmp = comment_node_new();

    tmp->child = split_comment(current_value);
    tmp->next = comments;

    comments = tmp;
}
